package com.gxgeek.redis.application.application.topintegral;

import com.alibaba.fastjson.JSON;
import com.google.common.base.Joiner;
import com.gxgeek.redis.application.redistool.JedisExecutor;
import com.gxgeek.redis.application.redistool.key.RedisKey;
import lombok.extern.slf4j.Slf4j;
import redis.clients.jedis.Transaction;
import redis.clients.jedis.Tuple;

import java.time.LocalDateTime;
import java.util.Map;
import java.util.Random;
import java.util.Set;

/**
 *
 * @author gx
 * @version 1.0
 * @date 2017-09-28
 * @since JDK 1.8
 */
@Slf4j
public class TopService {
    //获取系统的换行符
    private final  static String lineSeparator = System.getProperty("line.separator", "\n");
    /**
     * 1、增长
     * 2、查看
     */

    /**
     * 增加一个用户在某个标签下的积分
     * 如果该用户存在则值增加该用户分数
     * 如果该用户不存在则添加该用户及其分数
     * 默认是今天
     *
     * @param tag
     * @param uid   用户的ID
     * @param score 增加的分数
     * @return
     */
    public void incrTag(String tag, String uid, double score) {
        LocalDateTime date = LocalDateTime.now();
        incrTag(tag, uid, score, date);
    }

    /**
     * 增加一个用户在某个标签下的积分
     * 如果该用户存在则值增加该用户分数
     * 如果该用户不存在则添加该用户及其分数
     *
     * @param tag
     * @param uid   用户的ID
     * @param score 增加的分数
     * @param date  增加的时间
     * @return
     */
    public void incrTag(String tag, String uid, double score, LocalDateTime date) {
        //标签积分
        final String tagKey = RedisKey.TAG_TOP_SCORE.genKey(tag);
        //周积分
        final String weekKey = RedisKey.WEEK_TOP_SCORE.genDateKey(date);
        //标签月度积分
        final String tagMonthKey = RedisKey.TAG_TOP_SCORE.genKeyWithDate(tag, date);
        //日期积分   今日排行 周排行
        final String dateKey = RedisKey.DATE_TOP_SCORE.genDateKey(date);
        //月度积分
        final String mouthKey = RedisKey.MONTH_TOP_SCORE.genDateKey(date);
        log.info("incrTag ------ " + JSON.toJSONString(JedisExecutor.execute(jedis -> {
                    //这里使用事务保持原子性
                    Transaction transaction = jedis.multi();
                    transaction.zincrby(tagMonthKey, score, uid);
                    transaction.zincrby(dateKey, score, uid);
                    //只记录本周的所以设置过期时间避免浪费
                    transaction.expire(dateKey, 7 * 24 * 60 * 60);
                    transaction.zincrby(mouthKey, score, uid);
                    transaction.zincrby(tagKey, score, uid);
                    transaction.zincrby(weekKey, score, uid);
                    return transaction.exec();
                }
        )));
    }

    /**
     * 批量增加 排行版 分数 初始化分数
     *
     * @param tag
     * @param scoreMembers
     */
    public Long tagInit(final String tag, final Map<String, Double> scoreMembers) {
        final String tagKey = RedisKey.TAG_TOP_SCORE.genKey(tag);
        Long tagResult = JedisExecutor.execute(jedis -> jedis.zadd(tagKey, scoreMembers));
        log.debug("初始化了 " + tag + " 标签下的" + tagResult + "个成员");
        return tagResult;
    }





    /**
     * 今日排行
     * @param start
     * @param end
     */
    public Set<Tuple> todayTop(long start, long end) {
        //日期积分
        final String DateKey = RedisKey.DATE_TOP_SCORE.genDateKey(LocalDateTime.now());
        Set<Tuple> set = JedisExecutor.execute(jedis ->

                jedis.zrevrangeWithScores(DateKey, start, end)
        );
        return set;
    }


    /**
     * 获取便签排行榜指定名次范围人员
     *  @param tag
     * @param start
     * @param end
     */
    public Set<Tuple> tagTop(final String tag, long start, long end) {
        final String tagKey = RedisKey.TAG_TOP_SCORE.genKey(tag);
        Set<Tuple> set = JedisExecutor.execute(jedis -> jedis.zrevrangeWithScores(tagKey, start, end));
        return set;
    }

    /**
     * 查询几个标签排行的集合后的排行
     *  @param start
     * @param end
     * @param tags
     */
    public Set<Tuple> tagsTop(long start, long end, String... tags) {
        String tagsString = Joiner.on(",").join(tags);
        //根据 标签 生成每个标签的key
        String[] tagKeys = new String[tags.length];
        for (int i = 0; i < tags.length; i++) {
            tagKeys[i] = RedisKey.TAG_TOP_SCORE.genKey(tags[i]);
        }
        final String tagKey = RedisKey.TAG_TOP_SCORE.genKey(tagsString);
        Set<Tuple> set = (Set<Tuple>) JedisExecutor.executeWithPipline(jedis -> {
            //并集写入另一个key 中
            jedis.zunionstore(tagKey, tagKeys);
            //读取
            jedis.zrevrangeWithScores(tagKey, start, end);
        }).get(1);//获取第二个操作的结果
        return set;
    }

}
